/********************************************************************************
*                                                                               *
* kWookaApplicationMonitorPanel.cpp -- Show monitor information                 *
*                                                                               *
* Copyright (c) Fengren Technology(Guangzhou) Co.LTD. All rights reserved.      *
*                                                                               *
********************************************************************************/

#include "kWookaApplicationMonitorPanel.hpp"

#include "kWooka_ids.h"
#include "wxtimeserieschartctrl.h"
#include "wxcharts.h"

#include "kWookaApplicationViewPanel.hpp"
#include "kWooka_frame.hpp"

BEGIN_EVENT_TABLE(kWookaApplicationMonitorPanel, wxPanel)
    ////Manual Code Start
	EVT_THREAD(ID_EVENT_THREAD_MONITOR, kWookaApplicationMonitorPanel::OnPerformanceEvent)
    ////Manual Code End
    //EVT_KEY_DOWN(kPosSimpleCheckoutPanel::OnKeyCharEvent)
END_EVENT_TABLE()


wxString FormatCPUUsage(const wxString& lbl, double value) {
	return wxString::Format(wxT("%s: %.0f %%"), lbl, value);
}

wxString FormatMemoryUsage(const wxString& lbl, double value) {
	return wxString::Format(wxT("%s: %.0fMB"), lbl, value / 1024.0 / 1024.0);
}

wxString FormatDiskIOUsage(const wxString& lbl, double value) {
	return wxString::Format(wxT("%s: %.0f KB/s"), lbl, value / 1024.0);
}

wxString FormatNetworkBandwidth(const wxString& lbl, double value) {
	return wxString::Format(wxT("%s: %.0f KB/s"), lbl, value / 1024.0);
}

wxString FormatThreadCount(const wxString& lbl, double value) {
	return wxString::Format(wxT("%s: %.0f"), lbl, value);
}

wxString FormatHandleCount(const wxString& lbl, double value) {
	return wxString::Format(wxT("%s: %.0f"), lbl, value);
}

wxThread::ExitCode kWookaMonitorThread::Entry() {
	m_running = true;
	while (m_running) {
		m_monitorpanel->DoGetPerformanceInfo();
		Sleep(3000);
	}
	return NULL;
}

void kWookaMonitorThread::Shutdown() {
	m_running = false;
	Wait();
}

kWookaApplicationMonitorPanel::kWookaApplicationMonitorPanel(wxWindow *parent, wxWindowID id, const wxString& WXUNUSED(title), const wxPoint &position, const wxSize& size, long style)
: wxPanel(parent, id, position, size, style), m_monitorThread(this)
{
	m_executor = NULL;
	m_appitem = NULL;
	m_viewpanel = NULL;
    CreateGUIControls();
	m_monitorThread.Run();
}

kWookaApplicationMonitorPanel::~kWookaApplicationMonitorPanel()
{
	m_monitorThread.Shutdown();
	wxLogDebug(wxT("kWookaApplicationMonitorPanel destroyed."));
}

void kWookaApplicationMonitorPanel::CreateGUIControls()
{
    //Do not add custom code between
    //GUI Items Creation Start and GUI Items Creation End
    //wxDev-C++ designer will remove them.
    //Add the custom code before or after the blocks
    ////GUI Items Creation Start

    CreateContentPanel();
    
    Center();

    ////GUI Items Creation End
}

/**
    Create the Search panel
    1. Status, 2. Order No, 3. Order Name, 4. Pay Time
 */
void kWookaApplicationMonitorPanel::CreateContentPanel() {
	wxDateTime dt = wxDateTime::Now();

	wxVector<wxString> labels;
	labels.push_back(dt.FormatTime());
	wxChartsCategoricalData::ptr chartData = wxChartsCategoricalData::make_shared(labels);
	
	wxChartsCategoricalData::ptr chartData2 = wxChartsCategoricalData::make_shared(labels);

	// Add the first dataset
	wxVector<wxDouble> points1;
	points1.push_back(0);
	wxChartsDoubleDataset::ptr dataset1(new wxChartsDoubleDataset("", points1));
	wxVector<wxDouble> points2;
	points2.push_back(0);

	wxChartsDoubleDataset::ptr dataset2(new wxChartsDoubleDataset("", points2));
	chartData->AddDataset(dataset1);

	chartData2->AddDataset(dataset1);
	chartData2->AddDataset(dataset2);

	// Create the line chart widget from the constructed data
	m_memoryLineChartCtrl = new wxLineChartCtrl(this, wxID_ANY, chartData,
		wxCHARTSLINETYPE_STRAIGHT, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);
	m_cpuUsageLineChartCtrl = new wxLineChartCtrl(this, wxID_ANY, chartData,
		wxCHARTSLINETYPE_STRAIGHT, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);
	m_diskLineChartCtrl = new wxLineChartCtrl(this, wxID_ANY, chartData2,
		wxCHARTSLINETYPE_STRAIGHT, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);
	m_networkLineChartCtrl = new wxLineChartCtrl(this, wxID_ANY, chartData2,
		wxCHARTSLINETYPE_STRAIGHT, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);
	m_threadLineChartCtrl = new wxLineChartCtrl(this, wxID_ANY, chartData,
		wxCHARTSLINETYPE_STRAIGHT, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);
	m_handlerLineChartCtrl = new wxLineChartCtrl(this, wxID_ANY, chartData,
		wxCHARTSLINETYPE_STRAIGHT, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);

	wxBoxSizer* boxSizer = new wxBoxSizer(wxVERTICAL);
	wxBoxSizer* boxSizer1 = new wxBoxSizer(wxHORIZONTAL);
	wxBoxSizer* boxSizer2 = new wxBoxSizer(wxHORIZONTAL);
	wxBoxSizer* boxSizer3 = new wxBoxSizer(wxHORIZONTAL);

	m_cpuUsageLineChartCtrl->SetTitle(_("CPU Usage"));
	m_cpuUsageLineChartCtrl->SetTooltipFormat(FormatCPUUsage);
	m_memoryLineChartCtrl->SetTitle(_("Memory Usage"));
	m_memoryLineChartCtrl->SetTooltipFormat(FormatMemoryUsage);
	m_diskLineChartCtrl->SetTitle(_("Disk IO"));
	m_diskLineChartCtrl->SetTooltipFormat(FormatDiskIOUsage);
	m_networkLineChartCtrl->SetTitle(_("Network IO"));
	m_networkLineChartCtrl->SetTooltipFormat(FormatNetworkBandwidth);
	m_threadLineChartCtrl->SetTitle(_("Threads"));
	m_threadLineChartCtrl->SetTooltipFormat(FormatThreadCount);
	m_handlerLineChartCtrl->SetTitle(_("Handlers"));
	m_handlerLineChartCtrl->SetTooltipFormat(FormatHandleCount);

	boxSizer1->Add(m_cpuUsageLineChartCtrl, 1, wxEXPAND | wxALL, 5);
	boxSizer1->Add(m_memoryLineChartCtrl, 1, wxEXPAND | wxALL, 5);
	boxSizer2->Add(m_diskLineChartCtrl, 1, wxEXPAND | wxALL, 5);
	boxSizer2->Add(m_networkLineChartCtrl, 1, wxEXPAND | wxALL, 5);
	boxSizer3->Add(m_threadLineChartCtrl, 1, wxEXPAND | wxALL, 5);
	boxSizer3->Add(m_handlerLineChartCtrl, 1, wxEXPAND | wxALL, 5);
	
	boxSizer->Add(boxSizer1, 1, wxEXPAND | wxALL, 5);
	boxSizer->Add(boxSizer2, 1, wxEXPAND | wxALL, 5);
	boxSizer->Add(boxSizer3, 1, wxEXPAND | wxALL, 5);

    this->SetSizerAndFit(boxSizer);

}

void kWookaApplicationMonitorPanel::OnKeyCharEvent(wxKeyEvent& event){
    if (event.GetKeyCode() == WXK_RETURN){
    }
}

void kWookaApplicationMonitorPanel::SetViewPanel(kWookaApplicationViewPanel* vp) {
	m_viewpanel = vp;
}

kWookaApplicationViewPanel* kWookaApplicationMonitorPanel::GetViewPanel() {
	return m_viewpanel;
}


void kWookaApplicationMonitorPanel::UpdateAppItem(kWookaAppItemInfo* appItem) {
#ifdef ENABLE_CRITICAL_SECTION
	criticalSection.Enter();
#endif
	try {
		m_appitem = appItem;
		if (m_appitem != NULL) {
			m_executor = this->GetViewPanel()->GetWookaFrame()->GetProjectInfo()->runtime->GetExecutor(m_appitem->id);
			if (m_executor != NULL) {
				wxVector<kWookaProcessPerformanceInfo>& perms = m_executor->GetAllPerformances();
				UpdateMonitorChartData(perms);
			}
		}
		else {
			m_executor = NULL;
			wxVector<kWookaProcessPerformanceInfo> perms;
			kWookaProcessPerformanceInfo it;
			perms.push_back(it);
			UpdateMonitorChartData(perms);
		}
	}
	catch (std::exception& e) {
		wxLogDebug(e.what());
	}
#ifdef ENABLE_CRITICAL_SECTION
	criticalSection.Leave();
#endif
}

void kWookaApplicationMonitorPanel::DoGetPerformanceInfo() {
	if (this->GetViewPanel() != NULL && this->GetViewPanel()->GetWookaFrame() != NULL && this->GetViewPanel()->GetWookaFrame()->GetProjectInfo() != NULL) {
		wxVector<kWookaProcessExecutor*> vt = this->GetViewPanel()->GetWookaFrame()->GetProjectInfo()->runtime->GetAllExecutors();
		for (size_t s = 0; s < vt.size(); s++) {
			kWookaProcessExecutor* pe = vt[s];
			if (pe != NULL) {
				kWookaProcessPerformanceInfo perm = pe->GetProcessPerformance();
				if (m_executor != NULL && m_executor == pe && perm.success) {
					wxThreadEvent te(wxEVT_COMMAND_THREAD, ID_EVENT_THREAD_MONITOR);
					te.SetPayload(perm.Clone());
					QueueEvent(te.Clone());
				}
			}
		}
	}
}

void ConvertChartCategoricalDataPoint(kWookaProcessPerformanceInfo* perm, 
	wxVector<wxString>& lbls,
	wxVector<wxDouble>& pt1, 
	wxVector<wxDouble>& pt2, 
	wxVector<wxDouble>& pt3, 
	wxVector<wxDouble>& pt4, 
	wxVector<wxDouble>& pt5, 
	wxVector<wxDouble>& pt6, 
	wxVector<wxDouble>& pt7, 
	wxVector<wxDouble>& pt8) {
	lbls.push_back(perm->timestamp);
	pt1.push_back(perm->cpuUsages);
	pt2.push_back(perm->memoryUsed);
	pt3.push_back(perm->diskReadSpeed);
	pt4.push_back(perm->networkRecvSpeed);
	pt5.push_back(perm->threads);
	pt6.push_back(perm->handlers);
	pt7.push_back(perm->diskWriteSpeed);
	pt8.push_back(perm->networkSendSpeed);
}

void ConvertChartCategoricalDataSet(wxVector<kWookaProcessPerformanceInfo>& perms,
	wxVector<wxString>& lbls,
	wxVector<wxDouble>& pt1,
	wxVector<wxDouble>& pt2,
	wxVector<wxDouble>& pt3,
	wxVector<wxDouble>& pt4,
	wxVector<wxDouble>& pt5,
	wxVector<wxDouble>& pt6,
	wxVector<wxDouble>& pt7,
	wxVector<wxDouble>& pt8) {
	for (size_t s = 0; s < perms.size(); s++) {
		kWookaProcessPerformanceInfo& perm = perms[s];
		ConvertChartCategoricalDataPoint(&perm, lbls, pt1, pt2, pt3, pt4, pt5, pt6, pt7, pt8);
	}
}

void kWookaApplicationMonitorPanel::OnPerformanceEvent(wxThreadEvent& event) {
	// Do the wxLineChartCtrl redraw
	wxVector<wxString> labels;
	wxVector<wxDouble> points1;
	wxVector<wxDouble> points2;
	wxVector<wxDouble> points3;
	wxVector<wxDouble> points4;
	wxVector<wxDouble> points5;
	wxVector<wxDouble> points6;
	wxVector<wxDouble> points7;
	wxVector<wxDouble> points8;
	bool success = false;
	kWookaProcessPerformanceInfo* perm = (kWookaProcessPerformanceInfo*)event.GetPayload<kWookaProcessPerformanceInfo*>();
	if (perm != NULL) {
		success = perm->success;
		if (success) {
			ConvertChartCategoricalDataPoint(perm, labels, points1, points2, points3, points4, points5, points6, points7, points8);
		}
		delete perm;
	}
	if (!success) {
		return;
	}

	wxChartsCategoricalData::ptr chartData1 = wxChartsCategoricalData::make_shared(labels);
	wxChartsCategoricalData::ptr chartData2 = wxChartsCategoricalData::make_shared(labels);
	wxChartsCategoricalData::ptr chartData3 = wxChartsCategoricalData::make_shared(labels);
	wxChartsCategoricalData::ptr chartData4 = wxChartsCategoricalData::make_shared(labels);
	wxChartsCategoricalData::ptr chartData5 = wxChartsCategoricalData::make_shared(labels);
	wxChartsCategoricalData::ptr chartData6 = wxChartsCategoricalData::make_shared(labels);
	
	// Add the first dataset


	 // clear it;

	wxChartsDoubleDataset::ptr dataset1(new wxChartsDoubleDataset(_("CPU"), points1));
	wxChartsDoubleDataset::ptr dataset2(new wxChartsDoubleDataset(_("Memory"), points2));
	wxChartsDoubleDataset::ptr dataset3(new wxChartsDoubleDataset(_("Read"), points3));
	wxChartsDoubleDataset::ptr dataset7(new wxChartsDoubleDataset(_("Write"), points7));
	wxChartsDoubleDataset::ptr dataset4(new wxChartsDoubleDataset(_("Recv"), points4));
	wxChartsDoubleDataset::ptr dataset8(new wxChartsDoubleDataset(_("Send"), points8));
	wxChartsDoubleDataset::ptr dataset5(new wxChartsDoubleDataset(_("Thread"), points5));
	wxChartsDoubleDataset::ptr dataset6(new wxChartsDoubleDataset(_("Handlers"), points6));

	chartData1->AddDataset(dataset1);
	chartData2->AddDataset(dataset2);
	chartData3->AddDataset(dataset3);
	chartData3->AddDataset(dataset7);
	chartData4->AddDataset(dataset4);
	chartData4->AddDataset(dataset8);
	chartData5->AddDataset(dataset5);
	chartData6->AddDataset(dataset6);
#ifdef ENABLE_CRITICAL_SECTION
	criticalSection.Enter();
#endif
	try {
		m_cpuUsageLineChartCtrl->AddData(chartData1);
		m_memoryLineChartCtrl->AddData(chartData2);
		m_diskLineChartCtrl->AddData(chartData3);
		m_networkLineChartCtrl->AddData(chartData4);
		m_threadLineChartCtrl->AddData(chartData5);
		m_handlerLineChartCtrl->AddData(chartData6);
	}
	catch (std::exception& e) {
		OutputDebugStringA(e.what());
	}
#ifdef ENABLE_CRITICAL_SECTION
	criticalSection.Leave();
#endif
}


void kWookaApplicationMonitorPanel::UpdateMonitorChartData(wxVector<kWookaProcessPerformanceInfo>& perms) {
	if (perms.size() > 0) {
		wxVector<wxString> labels;
		wxVector<wxDouble> points1;
		wxVector<wxDouble> points2;
		wxVector<wxDouble> points3;
		wxVector<wxDouble> points4;
		wxVector<wxDouble> points5;
		wxVector<wxDouble> points6;
		wxVector<wxDouble> points7;
		wxVector<wxDouble> points8;
		ConvertChartCategoricalDataSet(perms, labels, points1, points2, points3, points4, points5, points6, points7, points8);
		wxChartsCategoricalData::ptr chartData1 = wxChartsCategoricalData::make_shared(labels);
		wxChartsCategoricalData::ptr chartData2 = wxChartsCategoricalData::make_shared(labels);
		wxChartsCategoricalData::ptr chartData3 = wxChartsCategoricalData::make_shared(labels);
		wxChartsCategoricalData::ptr chartData4 = wxChartsCategoricalData::make_shared(labels);
		wxChartsCategoricalData::ptr chartData5 = wxChartsCategoricalData::make_shared(labels);
		wxChartsCategoricalData::ptr chartData6 = wxChartsCategoricalData::make_shared(labels);


		wxChartsDoubleDataset::ptr dataset1(new wxChartsDoubleDataset(_("CPU"), points1));
		wxChartsDoubleDataset::ptr dataset2(new wxChartsDoubleDataset(_("Memory"), points2));
		wxChartsDoubleDataset::ptr dataset3(new wxChartsDoubleDataset(_("Read"), points3));
		wxChartsDoubleDataset::ptr dataset7(new wxChartsDoubleDataset(_("Write"), points7));
		wxChartsDoubleDataset::ptr dataset4(new wxChartsDoubleDataset(_("Recv"), points4));
		wxChartsDoubleDataset::ptr dataset8(new wxChartsDoubleDataset(_("Send"), points8));
		wxChartsDoubleDataset::ptr dataset5(new wxChartsDoubleDataset(_("Thread"), points5));
		wxChartsDoubleDataset::ptr dataset6(new wxChartsDoubleDataset(_("Handlers"), points6));

		chartData1->AddDataset(dataset1);
		chartData2->AddDataset(dataset2);
		chartData3->AddDataset(dataset3);
		chartData3->AddDataset(dataset7);
		chartData4->AddDataset(dataset4);
		chartData4->AddDataset(dataset8);
		chartData5->AddDataset(dataset5);
		chartData6->AddDataset(dataset6);
#ifdef ENABLE_CRITICAL_SECTION
		criticalSection.Enter();
#endif
		try {
			m_cpuUsageLineChartCtrl->ReInitializeData(chartData1);
			m_memoryLineChartCtrl->ReInitializeData(chartData2);
			m_diskLineChartCtrl->ReInitializeData(chartData3);
			m_networkLineChartCtrl->ReInitializeData(chartData4);
			m_threadLineChartCtrl->ReInitializeData(chartData5);
			m_handlerLineChartCtrl->ReInitializeData(chartData6);
		}
		catch (std::exception& e) {
			OutputDebugStringA(e.what());
		}
#ifdef ENABLE_CRITICAL_SECTION
		criticalSection.Leave();
#endif
	}
}